package com.cnbm.wcsbasic.protocol.netty.io.common.enmuc;


import com.cnbm.wcsbasic.protocol.netty.io.common.byteutils.ByteUtils;
import com.cnbm.wcsbasic.protocol.netty.io.common.byteutils.StringArrayStruc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

public enum PlcVarType {
    //单体变量
    BOOL("BOOL",1,1,false), //特殊
    BYTE("BYTE",1,2,false),
    WORD("WORD",2,3,false),
    DWORD("DWORD",4,4,false),
    LWORD("LWORD",8,5,false),
    INT("INT",2,6,false),
    UINT("UINT",2,7,false),
    SINT("SINT",1,8,false),
    USINT("USINT",1,9,false),
    DINT("DINT",4,10,false),
    UDINT("UDINT",4,11,false),
    LINT("LINT",8,12,false),
    ULINT("ULINT",8,13,false),
    REAL("REAL",4,14,false),  //特殊
    LREAL("LREAL",8,15,false), //特殊，看结构
    CHAR("CHAR",1,16,false),
    WCHAR("WCHAR",2,17,false),
    STRING("STRING",1,18,false),  //特殊

    //todo  Array 再搞一搞。
    BOOL_Array("BOOL",1,1,true),  //特殊
    BYTE_Array("BYTE",1,2,true),
    WORD_Array("WORD",2,3,true),
    DWORD_Array("DWORD",4,4,true),
    CHAR_Array("CHAR",1,5,true),
    SINT_Array("SINT",1,6,true),
    INT_Array("INT",2,7,true),
    DINT_Array("DINT",4,8,true),
    UINT_Array("UINT",2,9,true),
    USINT_Array("USINT",1,10,true),
    UDINT_Array("UDINT",4,11,true),
    LINT_Array("LINT",8,12,true),
    REAL_Array("REAL",4,14,true),
    LREAL_Array("LREAL",8,15,true),
    STRING_Array("STRING",4,18,true),
    ;
    private static final Logger logger = LoggerFactory.getLogger(PlcVarType.class);

//    private static final Map<TransportSize, PlcVar> map;
//    static {
//        map = new HashMap<>();
//        for (PlcVar value : PlcVar.values()) {
//            if(!value.isArray){
//                map.put(value.getTransportSize(), value);
//            }
//        }
//    }
//    public static PlcVar valueOf(TransportSize transportSize){
//        return map.get(transportSize);
//    }


    private String name;
    //这种数据类型的 byte长度
    private Integer dataSize;
    private Integer dataType;
    private boolean isArray;


    PlcVarType(String name, Integer dataSize, Integer dataType, Boolean isArray){
        this.name = name;
        this.dataSize = dataSize;
        this.dataType = dataType;
        this.isArray = isArray;
    }

    public Integer getDataSize() {
        return dataSize;
    }


    public String getName() {
        return name;
    }

    public boolean isArray() {
        return isArray;
    }

    public byte[] toBytes(Object value){
        //todo here 扩展数组 toBytes
        if(!isArray){
            byte[] res = null;
            switch (dataType) {
                case 1:
                    res = ByteUtils.boolToBytes((boolean)value);
                    break;
                case 2:
                    //ByteUtils.setbytes(Byte.valueOf((byte) 0xFF))
                    res = ByteUtils.setbytes(Byte.valueOf((byte) value));
                    break;
                case 3:
                    //ByteUtils.wordToBytes(Short.valueOf("-55"))
                    res = ByteUtils.wordToBytes(Short.valueOf(value.toString()));
                    break;
                case 4:
                    //ByteUtils.dwordToBytes(99)
                    res = ByteUtils.dwordToBytes((int)value);
                    break;
                case 5:
                    //null
                    break;
                case 6:
                    //ByteUtils.intToBytes(-99)
                    res = ByteUtils.intToBytes((int)value);
                    break;
                case 7:
                    //ByteUtils.uintToBytes(9)
                    res = ByteUtils.uintToBytes((int)value);
                    break;
                case 8:
                    //ByteUtils.sintToBytes(-9)
                    res =ByteUtils.sintToBytes((int)value);
                    break;
                case 9:
                    //ByteUtils.usintToBytes(9);
                    res =ByteUtils.usintToBytes((int)value);
                    break;
                case 10:
                    //ByteUtils.dintToBytes(-999)
                    res =ByteUtils.dintToBytes((int)value);
                    break;
                case 11:
                    //ByteUtils.udintToBytes(99)
                    res =ByteUtils.udintToBytes((int)value);
                    break;
                case 12:
                    //LINT
                    res = ByteUtils.longToBytes(Long.parseLong(value.toString()));
                    break;
                case 13:
                    //待补充
                    break;
                case 14:
                    //ByteUtils.realToBytes(Float.valueOf("-11.2"))
                    res =ByteUtils.realToBytes(Float.valueOf(value.toString()));
                    break;
                case 15:
                    //ByteUtils.lrealToBytes(Double.parseDouble("-111.1"));
                    res =ByteUtils.lrealToBytes(Double.parseDouble(value.toString()));
                    break;
                case 16:
                    //ByteUtils.charToBytes('b')
                    res =ByteUtils.charToBytes((char)value);
                    break;
                case 17:
                    //ByteUtils.wcharToBytes('菜')
                    res =ByteUtils.wcharToBytes((char)value);
                    break;
                case 18:
                    //String s = "你好啊";
                    //ByteUtils.strToBytes(s);
                    res = ByteUtils.strToBytes(value.toString());
                    break;
                case 19:
                    //待补充
                    break;
                case 20:
                    //不常用 待补充
                    break;
                case 21:
                    //不常用
                    break;
                case 22:
                    //不常用
                    break;
                case 23:
                    ////不常用
                    break;
                case 24:
                    ////不常用
                    break;
                case 25:
                    //不常用
                    break;
                case 26:
                    //不常用
                    break;
                case 27:
                    //不常用
                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }else {
            byte[] res = null;
            switch (dataType) {
                case 1:
                    //res = ByteUtils.booleanArrayToBytes((boolean[]) value);
                    res = ByteUtils.toByteArray((boolean[]) value);
                    break;
                case 2:


                //方式1
//                    byte[] v = (byte[]) value;
//                    List<Byte> vlist = new ArrayList<Byte>();
//                    for (int i=0;i<v.length;i++) {
//                        vlist.add(v[i]);
//                        vlist.add((byte)0);
//                    }
//                    byte[] ret = new byte[vlist.size()];
//                    for (int i=0;i<ret.length;i++) {
//                        ret[i] = vlist.get(i);
//                    }
//                    res = ret;

                    //方式2
                    res = (byte[]) value;

                    break;
                case 3:
//                    short[] shortArrays_content = new short[2];
//                    shortArrays_content[0] = 1;
//                    shortArrays_content[1] = -1;
//
                    res = ByteUtils.wordArrayToBytes((short[]) value);
                    break;
                case 4:
//                  int[] intArrays_content = new int[2];
//                  intArrays_content[0] = 1;
//                  intArrays_content[1] = -1;
//
                    res = ByteUtils.dwordArrayToBytes((int[]) value);
                    break;
                case 5:
//                  char[] charArrays_content = new char[2];
//                  charArrays_content[0] = '1';
//                  charArrays_content[1] = 'b';
//
                    res = ByteUtils.charArrayToBytes((char[]) value);
                    break;
                case 6:
//                  int[] sintArrays_content = new int[2];
//                  sintArrays_content[0] = 1;
//                  sintArrays_content[1] = -1;
//
                    res = ByteUtils.sintArrayToBytes((int[]) value);
                    break;
                case 7:
//                  int[] iintArrays_content = new int[2];
//                  iintArrays_content[0] = 12;
//                  iintArrays_content[1] = -21;
//
                    res = ByteUtils.intArrayToBytes((int[]) value);
                    break;
                case 8:
//                  int[] dintArrays_content = new int[2];
//                  dintArrays_content[0] = 12;
//                  dintArrays_content[1] = -21;
//
                    res = ByteUtils.dintArrayToBytes((int[]) value);
                    break;
                case 9:
//                    int[] uintArrays_content = new int[3];
//                    uintArrays_content[0] = 12;
//                    uintArrays_content[1] = 99;
//                    uintArrays_content[2] = 1;
                    res = ByteUtils.uintArrayToBytes((int[]) value);
                    break;
                case 10:
//                    int[] usintArrays_content = new int[3];
//                    usintArrays_content[0] = 12;
//                    usintArrays_content[1] = 99;
//                    usintArrays_content[2] = 1;
                    res = ByteUtils.usintArrayToBytes((int[]) value);
                    break;
                case 11:
//                    int[] udintArrays_content = new int[3];
//                    udintArrays_content[0] = 12;
//                    udintArrays_content[1] = 99;
//                    udintArrays_content[2] = 1;
                    res = ByteUtils.udintArrayToBytes((int[]) value);
                    break;
                case 12:
                    //lint_array
                    res = ByteUtils.longArrayToBytes((List<Long>) value);
                    break;
                case 13:
                    //

                    break;
                case 14:
                    //real array
                    res = ByteUtils.realArrayToBytes((List<Float>)value);
                    break;
                case 15:
                    //lreal array
                    res = ByteUtils.lrealArrayToBytes((List<Double>)value);
                    break;
                case 18:
                    //string_array
                    StringArrayStruc strus = (StringArrayStruc)value;
                    res = ByteUtils.strArrayToBytes(strus.getContent(),strus.getStrSize());
                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }
    }

    //todo here 把 read 和 write操作都封装一下 然后 和 toByte 和 toObject 整合
    /**
     * PlcVar(byte[])  转  java对象    对照表
     * 单体变量
     * Bool       ===>      Boolean
     * LREAL      ===>      Double
     * REAL       ===>      Float
     * DATE       ===>      String(yyyy-MM-dd 这种形式的类型)
     * DTL        ===>      String("年-月-日-工作日-时-分-秒" 这种格式)
     * TIME       ===>      Integer(单位 ms)
     * USINT      ===>      Integer
     * SINT       ===>      Integer
     * UINT       ===>      Integer
     * INT        ===>      Integer
     * DINT       ===>      Integer
     * UINT       ===>      Long
     * Byte       ===>      Integer(有符号)(默认)
     *                     Integer(无符号)(后续扩展)
     * Char       ===>      Character
     * WChar      ===>      Character
     * String     ===>      String                    //注意： String类型 不能用枚举类里的 toObject() / toBytes() 的方法，具体方式看Demo


     * 数组变量
     * BoolArray      ===>      List<Boolean>
     * ByteArray      ===>      List<Byte>
     * WordArray      ===>      List<Integer>
     * DWordArray     ===>      List<Integer>
     * CharArray      ===>      List<Character>
     * SIntArray      ===>      List<Integer>
     * IntArray       ===>      List<Integer>
     * DIntArray      ===>      List<Integer>
     * UIntArray      ===>      List<Integer>
     * USIntArray     ===>      List<Integer>
     * UDIntArray     ===>      List<Long>
     * StringArray    ===>      List<String>         //注意： String类型 不能用枚举类里的 toObject() / toBytes() 的方法，具体方式看Demo
     *
     *
     * */
    public Object toObject(byte[] value) {
        if(!isArray){
            Object res = null;
            switch (dataType) {
                case 1:
                    //
                    res = ByteUtils.toBoolean(value);
                    break;
                case 2:
                    res = ByteUtils.toInt(value[0]);
                    break;
                case 3:
                    //
                    res = ByteUtils.toInt(value[0],value[1]);
                    break;
                case 4:
                    //
                    res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
                    break;
                case 5:
                    //null
                    break;
                case 6:
                    //
                    res = ByteUtils.toUInt(value[0],value[1]);
                    break;
                case 7:
                    //
                    res = ByteUtils.toUInt(value[0],value[1]);
                    break;
                case 8:
                    //
                    res = ByteUtils.toUInt(value[0]);
                    break;
                case 9:
                    //
                    res = ByteUtils.toUInt(value[0]);
                    break;
                case 10:
                    //
                    res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
                    break;
                case 11:
                    //
                    res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);

                    break;
                case 12:
                    //LINT
                    res = ByteUtils.toLong(value,0,false);
                    break;
                case 13:
                    //ULINT 待补充

                    break;
                case 14:
                    //
                    res = ByteUtils.realbytesToFloat(value);
                    break;
                case 15:
                    //ByteUtils.lrealbytesToDouble(lreal)
                    res = ByteUtils.lrealbytesToDouble(value);
                    break;
                case 16:
                    //
                    res = ByteUtils.toChar(value);
                    break;
                case 17:
                    //
                    res = ByteUtils.toChar(value);
                    break;
                case 18:
                    //string parse
                    res = ByteUtils.toStr(value);
                    break;
                case 19:
                    //

                    break;
                case 20:
                    //
                    res = ByteUtils.toInt(value[0], value[1], value[2], value[3]);
                    break;
                case 21:
                    //

                    break;
                case 22:
                    //

                    Long aLong = Long.valueOf(ByteUtils.toInt(value[0], value[1]).toString());
                    String s = ByteUtils.addDate("1990-01-01", aLong);
                    res = s;
                    break;
                case 23:
                    //

                    break;
                case 24:
                    //

                    break;
                case 25:
                    //

                    break;
                case 26:
                    //

                    break;
                case 27:
                    //
                    byte[] year = new byte[2];
                    year[0] = value[0];
                    year[1] = value[1];
                    Integer yearInt = ByteUtils.toInt(year[0], year[1]);
                    Integer monthInt = ByteUtils.toInt(value[2]);
                    Integer dayInt = ByteUtils.toInt(value[3]);
                    Integer worddayInt = ByteUtils.toInt(value[4]);
                    Integer hourInt = ByteUtils.toInt(value[5]);
                    Integer minuInt = ByteUtils.toInt(value[6]);
                    Integer secondInt = ByteUtils.toInt(value[7]);
                    res = yearInt+"-"+monthInt+"-"+dayInt+"-"+worddayInt+"-"+hourInt+"-"+minuInt+"-"+secondInt;
                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }else {
            Object res = null;
            switch (dataType) {
                case 1:
                    //
//                    res = ByteUtils.toBoolArray(value);
                    res = ByteUtils.toBoolArray(value);
                    break;
                case 2:
                    //
                    res = ByteUtils.toByteArray(value);
                    break;
                case 3:
                    //
                    res = ByteUtils.toWordArray(value);
                    break;
                case 4:
                    //
                    res = ByteUtils.toDWordArray(value);
                    break;
                case 5:
                    //
                    res = ByteUtils.toCharArray(value);
                    break;
                case 6:
                    //
                    res =ByteUtils.toSIntArray(value);
                    break;
                case 7:
                    res = ByteUtils.toIntArray(value);
                    break;
                case 8:
                    res = ByteUtils.toDIntArray(value);
                    break;
                case 9:
                    res = ByteUtils.toUIntArray(value);
                    break;
                case 10:
                    res = ByteUtils.toUSIntArray(value);
                    break;
                case 11:
                    res = ByteUtils.toUDIntArray(value);
                    break;
                case 12:
                    //LINT ARRAY
                    res = ByteUtils.toLongArray(value,false);
                    break;
                case 14:
                    //real array
                    res = ByteUtils.toRealArray(value);
                    break;
                case 15:
                    //lreal array
                    res = ByteUtils.toLrealArray(value);
                    break;
                case 18:
                    //string array parse
                    res = ByteUtils.toStrArray(value);
                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }
    }

    /**
     * area               :DB块  或者其他块
     * areaNumber         :数据块编号  DB3
     * byteOffset         :字节偏移量
     * byteOffset         :比特偏移量（不填就是0  ，差不多只有读bool类型才会用到）
     * length             :长度（1 代表单个变量 ，2/3/4  代表读一个数组。）
     * */



}
